package com.woniuxy.filter;

import com.woniuxy.entity.User;
import com.woniuxy.enums.TokenStatusEnum;
import com.woniuxy.utils.JWTUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class JWTGlobalFilter implements GlobalFilter, Ordered {
    @Resource
    RedisTemplate redisTemplate;

    //用于过滤JWT，header中的token
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //从请求头获取key为Authorization的值
        List<String> authorization = exchange.getRequest().getHeaders().get("Authorization");
        List<String> refreshTokenList = exchange.getRequest().getHeaders().get("RefreshToken");
        if (authorization != null && refreshTokenList != null) {
            String token = authorization.get(0);
            String refreshToken = refreshTokenList.get(0);
            //校验token
            TokenStatusEnum verify = JWTUtils.verify(token);
            if (verify.equals(TokenStatusEnum.TOKEN_SUCCESS)) {
                // 成功
                return chain.filter(exchange);
            } else if (verify.equals(TokenStatusEnum.TOKEN_EXPIRE)) {
                //JWT过期，但refreshToken还未过期，重新生成token
                User user = (User)redisTemplate.opsForValue().get(refreshToken);
                if (user != null) {
                    return Mono.error(new ArithmeticException("长时间未操作，请重新登入"));
                }else {
                    // 30-60min有操作，refreshToken存在，重新生成token
                    String newToken = JWTUtils.generateToken(user.getUsername());
                    exchange.getResponse().getHeaders().set("token", newToken);
                    // 重新对refreshToken计时
                    redisTemplate.expire(refreshToken, 60, TimeUnit.MINUTES);
                    return chain.filter(exchange);
                }
            }else {
                // token是bad，或被篡改，重新登录
                redisTemplate.delete(refreshToken);
                return Mono.error(new ArithmeticException("token被篡改，请重新登录"));
            }
        }else { //无token
            if ("/auth/login".equals(exchange.getRequest().getPath().toString())){
                //登录放行
                return chain.filter(exchange);
            }else {
                //判断该链接是否需要登录认证或者某个角色(白名单)
            }
        }
        return chain.filter(exchange);
    }

    //优先级排序
    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
